home *** CD-ROM | disk | FTP | other *** search
/ AOL File Library: 2,801 to 2,900 / aol-file-protocol-4400-2801-to-2900.zip / AOLDLs / C++ Files Library / SK (Sockects) 1.4.1 r2 / SK v1.4.1 r2.sit / SK 1.4.1 r2 / SK / SK Sources / SK_TCP.cc < prev    next >
Text File  |  1994-06-13  |  33KB  |  1,291 lines

  1. /***************************************************************************
  2. * Copyright ⌐ 1992-1994 Matthias Neeracher and the Decision Systems Group
  3. * Permission is granted to anyone to use this software for any purpose on
  4. * any computer system, and to redistribute it freely, subject to the
  5. * following restrictions:
  6. * 1) The authors and the Decision Systems Group are not responsible for 
  7. *    the direct or indirect consequences of use of this software, no matter 
  8. *    how awful, even if they arise from defects in the software itself.
  9. *    This restriction applies to the use of this and any derived source code 
  10. *    and also to the use of all binary produced from this and any derived 
  11. *    source code.
  12. * 2) The origin and copyrights of this software must not be misrepresented, 
  13. *    either by explicit claim or by omission or alteration of copyright or
  14. *    authorship header information in this file or in any derived file.
  15. * 3) Altered or derived versions must be plainly marked as such, and must not
  16. *    be misrepresented as being the original software.
  17. * We encourage users of this software to provide feedback, bug fixes,
  18. * and enhancements to the authors for incorporation into future releases.
  19. *
  20. * ==========================================================================
  21. * FILE: SK_INET.cc
  22. * AUTHOR: Matthias Neeracher and Stephan Deibel
  23. * CREATION DATE: 12Aug92
  24. * VERSION: 13Jun94
  25. * DESCRIPTION: 
  26. *
  27. * TCP stream sockets implementation
  28. * NOTES: 
  29. * 0) This code was derived from Matthias Neerarcher's GUSI 1.1.0 and
  30. *    the socket library written by Charlie Reiman (creiman@ncsa.uiuc.edu)
  31. *    and Tom Milligan (milligan@madhaus.utcs.utoronto.ca); Copyrights
  32. *    are subject to this origin.
  33. *
  34. * MODIFICATIONS: 
  35. * --------------------------------------------------------------------------
  36. * Date     Name      Description of modification
  37. * --------------------------------------------------------------------------
  38. * 08Sep92    MN       A big part should work now                
  39. * 08Jan93    MN       tcp_notify was setting the wrong state to unconnected
  40. * 17Jan93    MN       Be more careful about user interrupts.
  41. * 21Jan93    MN       Simplify and correct code
  42. * 31Jan93    MN       Support for inetd
  43. * 13Jul93    SD       Port to THINK C++ 6.0
  44. * 21Jul93    SD       Subsetted to only TCP/UDP, applied DSG naming 
  45. *                    conventions and commenting guidelines, and
  46. *                    changed name to "SK" for clear distinction from
  47. *                    the GUSI code from which this was derived
  48. * 13Jun94   SD       Updated based on relevant changes to GUSI (through 1.4.1)
  49. */
  50.  
  51.  
  52. #include "SK_INET_P.hh"
  53.  
  54. /* All completion procedures must use "C" calling and not "C++" -- needed */
  55. /* primarily because of bugs with the THINK C++ 6.0 compiler */
  56.  
  57. extern "C" {
  58.  
  59.  
  60. /**************************************************************************/ 
  61. /**************************************************************************/ 
  62. /* Completion procedures */
  63.  
  64. /*************************************************************************** *
  65. * FUNCTION:
  66. *
  67. * tcp_notify
  68. *
  69. * DESCRIPTION:
  70. *
  71. * TCP notify call back
  72. *
  73. * PARAMETERS:
  74. *
  75. * StreamPtr                -- ???
  76. * u_short                -- ???
  77. * Ptr                    -- ???
  78. * u_short                -- ???
  79. * struct ICMPReport        -- ???
  80. *
  81. */
  82.  
  83. pascal void tcp_notify(
  84.     StreamPtr,
  85.     u_short                    eventCode,
  86.     Ptr                        userDataPtr,
  87.     u_short,
  88.     struct ICMPReport *)
  89. {
  90.     CSK_TCPSocket *    sock    =    *(CSK_TCPSocket **) userDataPtr;
  91.  
  92.     switch (eventCode) {
  93.     case TCPClosing:
  94.         sock->fSocketState = SKk_STATE_CLOSING;
  95.         break;
  96.  
  97.     case TCPTerminate:
  98.         sock->fSocketState = SKk_STATE_UNCONNECTED;
  99.         break;
  100.     }
  101. }
  102.  
  103.  
  104. /*************************************************************************** *
  105. * FUNCTION:
  106. *
  107. * tcp_connect_done
  108. *
  109. * DESCRIPTION:
  110. *
  111. * TCP connect-done call back
  112. *
  113. * PARAMETERS:
  114. *
  115. * CSK_AnnotatedPB *        -- ???
  116. *
  117. */
  118.  
  119. void tcp_connect_done(CSK_AnnotatedPB *pb)
  120. {
  121.     CSK_TCPSocket *    sock = (CSK_TCPSocket *) pb->Owner();
  122.     TCPiopb * tcp = pb->TCP();
  123.  
  124.     if (!tcp->ioResult) {
  125.         sock->fMySocketAddress.sin_addr.s_addr         = tcp->csParam.open.localHost;
  126.         sock->fMySocketAddress.sin_port             = tcp->csParam.open.localPort;
  127.         sock->fPeerSocketAddress.sin_addr.s_addr    = tcp->csParam.open.remoteHost;
  128.         sock->fPeerSocketAddress.sin_port             = tcp->csParam.open.remotePort;
  129.         sock->fSocketState                             = SKk_STATE_CONNECTED;
  130.         sock->fLastAsyncErr                         = noErr;
  131.     }
  132.  
  133.     // Check for nasty error that once plagued us (will be removed eventually)
  134.     ASSERT(tcp->ioResult != inProgress);
  135. }
  136.  
  137.  
  138. /*************************************************************************** *
  139. * FUNCTION:
  140. *
  141. * tcp_listen_done
  142. *
  143. * DESCRIPTION:
  144. *
  145. * TCP listen-done call back
  146. *
  147. * PARAMETERS:
  148. *
  149. * CSK_AnnotatedPB *        -- ???
  150. *
  151. */
  152.  
  153. void tcp_listen_done(CSK_AnnotatedPB *pb)
  154. {
  155.     CSK_TCPSocket *    sock    =    (CSK_TCPSocket *) pb->Owner();
  156.     TCPiopb *    tcp    =    pb->TCP();
  157.  
  158.     switch(tcp->ioResult) {
  159.     case noErr:
  160.         sock->fPeerSocketAddress.sin_addr.s_addr    = tcp->csParam.open.remoteHost;
  161.         sock->fPeerSocketAddress.sin_port             = tcp->csParam.open.remotePort;
  162.         sock->fSocketState                     = SKk_STATE_LIS_CON;
  163.         sock->fLastAsyncErr                 = 0;
  164.         break;
  165.  
  166.     case openFailed:
  167.     case invalidStreamPtr:
  168.     case connectionExists:
  169.     case duplicateSocket:
  170.     case commandTimeout:
  171.     default:
  172.         sock->fSocketState                     = SKk_STATE_UNCONNECTED;
  173.         sock->fLastAsyncErr                 = tcp->ioResult;
  174.         break;
  175.     }
  176.  
  177.     // Check for nasty error that once plagued us (will be removed eventually)
  178.     ASSERT(tcp->ioResult != inProgress);
  179. }
  180.  
  181.  
  182. /*************************************************************************** *
  183. * FUNCTION:
  184. *
  185. * tcp_recv_done
  186. *
  187. * DESCRIPTION:
  188. *
  189. * TCP recv-done call back
  190. *
  191. * PARAMETERS:
  192. *
  193. * CSK_AnnotatedPB *        -- ???
  194. *
  195. */
  196.  
  197. void tcp_recv_done(CSK_AnnotatedPB *pb)
  198. {
  199.     CSK_TCPSocket *        sock    =    (CSK_TCPSocket *) pb->Owner();
  200.     TCPiopb *        tcp    =    pb->TCP();
  201.     register    int     readin;
  202.  
  203.     if (!tcp->ioResult) {
  204.         readin = tcp->csParam.receive.rcvBuffLen;
  205.         sock->fBytesReceived   = readin;
  206.     }
  207.  
  208.     // Check for nasty error that once plagued us (will be removed eventually)
  209.     ASSERT(tcp->ioResult != inProgress);
  210. }
  211.  
  212.  
  213. /*************************************************************************** *
  214. * FUNCTION:
  215. *
  216. * tcp_send_done
  217. *
  218. * DESCRIPTION:
  219. *
  220. * TCP send-done call back
  221. *
  222. * PARAMETERS:
  223. *
  224. * CSK_AnnotatedPB *        -- ???
  225. *
  226. */
  227.  
  228. void tcp_send_done(CSK_AnnotatedPB *pb)
  229. {
  230.     CSK_TCPSocket *    sock    =    (CSK_TCPSocket *) pb->Owner();
  231.     TCPiopb *    tcp    =    pb->TCP();
  232.  
  233.     switch (tcp->ioResult) {
  234.     case noErr:
  235.         ((wdsEntry *)(tcp->csParam.send.wdsPtr))->length = 0;    /* mark it free */
  236.         break;
  237.  
  238.     case ipNoFragMemErr:
  239.     case connectionClosing:
  240.     case connectionTerminated:
  241.     case connectionDoesntExist:
  242.         sock->fSocketState     = SKk_STATE_UNCONNECTED;
  243.         sock->fLastAsyncErr = ENOTCONN;
  244.         break;
  245.  
  246.     case ipDontFragErr:
  247.     case invalidStreamPtr:
  248.     case invalidLength:
  249.     case invalidWDS:
  250.     default:
  251.         sock->fSocketState     = SKk_STATE_UNCONNECTED;
  252.         sock->fLastAsyncErr = tcp->ioResult;
  253.         break;
  254.     }
  255.  
  256.     // Check for nasty error that once plagued us (will be removed eventually)
  257.     ASSERT(tcp->ioResult != inProgress);
  258. }
  259.  
  260. }  /* extern "C" */
  261.  
  262.  
  263.  
  264. /**************************************************************************/ 
  265. /**************************************************************************/ 
  266. /* CSK_TCPSocket members */
  267.  
  268.  
  269. /*************************************************************************** *
  270. * FUNCTION:
  271. *
  272. * CSK_TCPSocket::CSK_TCPSocket
  273. *
  274. * DESCRIPTION:
  275. *
  276. * Constructor for this class
  277. *
  278. */
  279.  
  280. CSK_TCPSocket::CSK_TCPSocket()
  281.     :    CSK_INETSocket()
  282. {
  283.     TCPiopb    pb;
  284.  
  285.     fSocketState = SKk_STATE_UNCONNECTED;
  286.     fSelf = new(CSK_TCPSocket *);
  287.     *fSelf = this;
  288.  
  289.     pb.ioCRefNum                     = SKg_INETSockets.Driver();
  290.     pb.csCode                         = TCPCreate;
  291.     pb.csParam.create.rcvBuff         = (char *) NewPtr(SKk_StreamBufferSize);
  292.     pb.csParam.create.rcvBuffLen     = SKk_StreamBufferSize;
  293.     pb.csParam.create.notifyProc     = tcp_notify;
  294.     pb.csParam.create.userDataPtr    = Ptr(fSelf);
  295.  
  296.     switch(PBControlSync(ParmBlkPtr(&pb)))
  297.     {
  298.         case noErr:                     break;
  299.         case invalidLength:             SK_Error(ENOBUFS);         return;
  300.         case invalidBufPtr:             SK_Error(ENOBUFS);         return;
  301.         case insufficientResources:     SK_Error(EMFILE);         return;
  302.         default:                         SK_Error(ENETDOWN);     return;
  303.     }
  304.  
  305.     fPeerSocketAddress.sin_family = AF_INET;
  306.     fPeerSocketAddress.sin_addr.s_addr = 0;
  307.     fPeerSocketAddress.sin_port = 0;
  308.  
  309.     bzero(&fPeerSocketAddress.sin_zero[0], 8);
  310.  
  311.     fLastAsyncErr = 0;
  312.     fStream = pb.tcpStream;
  313. }
  314.  
  315.  
  316. /*************************************************************************** *
  317. * FUNCTION:
  318. *
  319. * CSK_TCPSocket::CSK_TCPSocket
  320. *
  321. * DESCRIPTION:
  322. *
  323. * Constructor for this class
  324. *
  325. * PARAMETERS:
  326. *
  327. * StreamPtr            -- stream to use with this TCP socket
  328. *
  329. */
  330.  
  331. CSK_TCPSocket::CSK_TCPSocket(StreamPtr stream)
  332.     :    CSK_INETSocket(stream)
  333. {
  334.     AppleEvent theEvent, myReply;
  335.     AEDesc theAddress;
  336.     long theType = 'inet';
  337.     ProcPtr    theProc    = (ProcPtr) tcp_notify;
  338.     ProcessSerialNumber    PSN;
  339.  
  340.     fSelf = new(CSK_TCPSocket *);
  341.     *fSelf = this;
  342.     fLastAsyncErr = 0;
  343.  
  344.     GetCurrentProcess(&PSN);
  345.     AECreateDesc(typeApplSignature, (Ptr) &theType, sizeof(theType), &theAddress);
  346.     AECreateAppleEvent('INET', 'TNFY',  &theAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
  347.     
  348.     AEPutParamPtr(&theEvent, 'STRM', typeLongInteger, (Ptr) &fStream, sizeof(fStream));
  349.     AEPutParamPtr(&theEvent, 'ASR ', typeLongInteger, (Ptr) &theProc, sizeof(ProcPtr));
  350.     AEPutParamPtr(&theEvent, 'USRP', typeLongInteger, (Ptr) &fSelf, sizeof(long));
  351.     AEPutParamPtr(&theEvent, keyProcessSerialNumber, typeProcessSerialNumber, (Ptr) &PSN, sizeof(ProcessSerialNumber));
  352.     
  353.     AESend(&theEvent, &myReply, kAEWaitReply, kAEHighPriority, 120, nil, nil);
  354.  
  355.     AEDisposeDesc(&myReply);
  356.     AEDisposeDesc(&theEvent);
  357.     AEDisposeDesc(&theAddress);
  358.  
  359.     TCPiopb * pb;
  360.  
  361.     pb                = GetPB();
  362.     pb->csCode     = TCPStatus;
  363.  
  364.     PBControlSync(ParmBlkPtr(pb));
  365.     
  366.     fMySocketAddress.sin_addr.s_addr     =     pb->csParam.status.localHost;
  367.     fMySocketAddress.sin_port                =    pb->csParam.status.localPort;
  368.     fPeerSocketAddress.sin_addr.s_addr =     pb->csParam.status.remoteHost;
  369.     fPeerSocketAddress.sin_port            =    pb->csParam.status.remotePort;
  370.     
  371.     // Check for nasty error that once plagued us (will be removed eventually)
  372.     ASSERT(pb->ioResult != inProgress);
  373. }
  374.  
  375.  
  376. /*************************************************************************** *
  377. * FUNCTION:
  378. *
  379. * CSK_TCPSocket::CSK_TCPSocket
  380. *
  381. * DESCRIPTION:
  382. *
  383. * Constructor for this class
  384. *
  385. * PARAMETERS:
  386. *
  387. * CSK_TCPSocket *        -- Existing TCP socket to used as template for initialization
  388. *
  389. */
  390.  
  391. CSK_TCPSocket::CSK_TCPSocket(CSK_TCPSocket * sock)
  392. {
  393.     fStream    = sock->fStream;
  394.     fStatus    = sock->fStatus;
  395.     fNonBlocking= sock->fNonBlocking;
  396.     fReceiveBuf    = sock->fReceiveBuf;
  397.     fBytesReceived = sock->fBytesReceived;
  398.     fMySocketAddress = sock->fMySocketAddress;
  399.     fPeerSocketAddress = sock->fPeerSocketAddress;
  400.     fSocketState = sock->fSocketState;
  401.     fLastAsyncErr = 0;
  402.     
  403.     // The reason for this strange code is that fStream->userData points to
  404.     // sock.fSelf and cannot be changed while the stream is alive
  405.     
  406.     fSelf = sock->fSelf;
  407.     *fSelf = this;
  408.     sock->fSelf    = new(CSK_TCPSocket *);
  409.     *sock->fSelf = sock;
  410. }
  411.  
  412.  
  413. /*************************************************************************** *
  414. * FUNCTION:
  415. *
  416. * CSK_TCPSocket::~CSK_TCPSocket
  417. *
  418. * DESCRIPTION:
  419. *
  420. * Destructor for this class
  421. *
  422. */
  423.  
  424. CSK_TCPSocket::~CSK_TCPSocket()
  425. {
  426.     TCPiopb *    pb;
  427.  
  428.     do {
  429.         pb                = GetPB();
  430.         pb->csCode         = TCPStatus;
  431.  
  432.         PBControlSync(ParmBlkPtr(pb));
  433.  
  434.         // Check for nasty error that once plagued us (will be removed eventually)
  435.         ASSERT(pb->ioResult != inProgress);
  436.  
  437.         SAFESPIN(false, SKk_MISC, 0);
  438.     } while (!errno && pb->csParam.status.amtUnackedData > 0);
  439.  
  440.     pb = GetPB();
  441.     pb->ioCompletion = nil;
  442.     pb->csCode = TCPClose;
  443.     pb->csParam.close.validityFlags = timeoutValue | timeoutAction;
  444.     pb->csParam.close.ulpTimeoutValue = 60 /* seconds */;
  445.     pb->csParam.close.ulpTimeoutAction     = 1 /* 1:abort 0:report */;
  446.  
  447.     switch (PBControlAsync(ParmBlkPtr(pb)))
  448.     {
  449.         case noErr:
  450.         case connectionClosing:
  451.             break;
  452.         case connectionDoesntExist:
  453.         case connectionTerminated:
  454.             break;
  455.         case invalidStreamPtr:
  456.         default:
  457.             return;
  458.     }
  459.     
  460.     {
  461.         rdsEntry    rdsarray[SKk_TCPMaxWds+1];
  462.         int        passcount;
  463.         const int maxpass =4;
  464.  
  465.         pb                    =    GetPB();
  466.  
  467.         for (passcount=0; passcount<maxpass; passcount++) {
  468.             pb->csCode                                             = TCPNoCopyRcv;
  469.             pb->csParam.receive.commandTimeoutValue    = 1; /* seconds, 0 = blocking */
  470.             pb->csParam.receive.rdsPtr                     = (Ptr)rdsarray;
  471.             pb->csParam.receive.rdsLength                 = SKk_TCPMaxWds;
  472.  
  473.             if (PBControlSync(ParmBlkPtr(pb)))
  474.                 break;
  475.  
  476.             pb->csCode                                             = TCPRcvBfrReturn;
  477.             pb->csParam.receive.rdsPtr                     = (Ptr)rdsarray;
  478.  
  479.             PBControlSync(ParmBlkPtr(pb));
  480.  
  481.             // Check for nasty error that once plagued us (will be removed eventually)
  482.             ASSERT(pb->ioResult != inProgress);
  483.  
  484.             SAFESPIN(false, SKk_MISC, 0);
  485.             
  486.             if (errno)
  487.                 break;
  488.         }
  489.  
  490.  
  491.         if (passcount == maxpass) {        /* remote side isn't being nice */
  492.             /* then try again */
  493.  
  494.             PBControlSync(ParmBlkPtr(pb));
  495.  
  496.             // Check for nasty error that once plagued us (will be removed eventually)
  497.             ASSERT(pb->ioResult != inProgress);
  498.  
  499.             for (passcount=0; passcount<maxpass; passcount++) {
  500.                 pb->csCode                                             = TCPNoCopyRcv;
  501.                 pb->csParam.receive.commandTimeoutValue    = 1; /* seconds, 0 = blocking */
  502.                 pb->csParam.receive.rdsPtr                     = (Ptr)rdsarray;
  503.                 pb->csParam.receive.rdsLength                 = SKk_TCPMaxWds;
  504.  
  505.                 if (PBControlSync(ParmBlkPtr(pb)))
  506.                     break;
  507.  
  508.                 pb->csCode                                             = TCPRcvBfrReturn;
  509.                 pb->csParam.receive.rdsPtr                     = (Ptr)rdsarray;
  510.  
  511.                 PBControlSync(ParmBlkPtr(pb));
  512.  
  513.                 // Check for nasty error that once plagued us (will be removed eventually)
  514.                 ASSERT(pb->ioResult != inProgress);
  515.  
  516.                 SAFESPIN(false, SKk_MISC, 0);
  517.                 
  518.                 if (errno)
  519.                     break;
  520.             }
  521.  
  522.         }
  523.     }
  524.  
  525.     /* destroy the stream */
  526.     pb->csCode     = TCPRelease;
  527.  
  528.     if (PBControlSync(ParmBlkPtr(pb)))
  529.         return;
  530.  
  531.     // Check for nasty error that once plagued us (will be removed eventually)
  532.     ASSERT(pb->ioResult != inProgress);
  533.     
  534.     DisposPtr(pb->csParam.create.rcvBuff); /* there is no release pb */
  535.     
  536.     delete fSelf;
  537. }
  538.  
  539.  
  540. /*************************************************************************** *
  541. * FUNCTION:
  542. *
  543. * CSK_TCPSocket::GetPB
  544. *
  545. * DESCRIPTION:
  546. *
  547. * Get a TCP io parameter block for use with this TCP socket.  The
  548. * parameter block is obtained from the SKg_INETSockets domain object
  549. * and is set up for use specifically with this socket.
  550. *
  551. * RETURNS:
  552. *
  553. * TCPiopb *            -- The TCP io parameter block
  554. *
  555. */
  556.  
  557. TCPiopb * CSK_TCPSocket::GetPB()
  558. {
  559.     CSK_AnnotatedPB *    pb        =    SKg_INETSockets.GetPB();
  560.     pb->TCP()->ioCRefNum =    SKg_INETSockets.Driver();
  561.     pb->TCP()->tcpStream    =    fStream;
  562.  
  563.     pb->SetOwner(this);
  564.  
  565.     return pb->TCP();
  566. }
  567.  
  568.  
  569. /*************************************************************************** *
  570. * FUNCTION:
  571. *
  572. * CSK_TCPSocket::Available
  573. *
  574. * DESCRIPTION:
  575. *
  576. * Return number of bytes of unread data available on this socket
  577. *
  578. * RETURNS:
  579. *
  580. * u_long        -- The number of unread bytes available
  581. *
  582. */
  583.  
  584. u_long CSK_TCPSocket::Available()
  585. {
  586.     TCPiopb * pb;
  587.  
  588.     pb                = GetPB();
  589.     pb->csCode     = TCPStatus;
  590.  
  591.     PBControlSync(ParmBlkPtr(pb));
  592.  
  593.     // Check for nasty error that once plagued us (will be removed eventually)
  594.     ASSERT(pb->ioResult != inProgress);
  595.     
  596.     return pb->csParam.status.amtUnreadData;
  597. }
  598.  
  599.  
  600. /*************************************************************************** *
  601. * FUNCTION:
  602. * CSK_TCPSocket::connect
  603. *
  604. * DESCRIPTION:
  605. *
  606. * Initiate a connection on a MacTCP socket.  This call attempts to make a 
  607. * connection to another socket. The other socket is specified by an internet 
  608. * address and port.
  609. *
  610. * PARAMETERS:
  611. *
  612. * void *         -- The internet address and port
  613. * int            -- The length of the given internet address information
  614. *
  615. * RETURNS:
  616. *
  617. * If the connection or binding succeeds, then 0 is returned.
  618. * Otherwise a -1 is returned, and a more specific error code is stored in
  619. * errno:
  620. *
  621. *    EAFNOSUPPORT      The address family in addr is not AF_INET.
  622. *
  623. *    EHOSTUNREACH      The TCP connection came up half-way and then failed.
  624. *
  625. * NOTES:
  626. *
  627. * TCP sockets may successfully connect() only once;
  628. *
  629. */
  630.  
  631. int CSK_TCPSocket::connect(void * address, int addrlen)
  632. {
  633.     OSErr                    err;
  634.     struct sockaddr_in *    addr = (struct sockaddr_in *) address;
  635.     TCPiopb    *                pb;
  636.  
  637.     ASSERT(addrlen == sizeof(struct sockaddr_in));
  638.  
  639.     if (addr->sin_family != AF_INET)
  640.         return SK_Error(EAFNOSUPPORT);
  641.  
  642.     /* Make sure this socket can connect */
  643.     if (fSocketState == SKk_STATE_CONNECTING)
  644.         return SK_Error(EALREADY);
  645.     if (fSocketState != SKk_STATE_UNCONNECTED)
  646.         return SK_Error(EISCONN);
  647.  
  648.     fSocketState = SKk_STATE_CONNECTING;
  649.  
  650.     pb = GetPB();
  651.     pb->ioCompletion = TCPIOCompletionProc(tcp_connect_done);
  652.     pb->csCode = TCPActiveOpen;
  653.     pb->csParam.open.validityFlags = timeoutValue | timeoutAction;
  654.     pb->csParam.open.ulpTimeoutValue = 60 /* seconds */;
  655.     pb->csParam.open.ulpTimeoutAction = 1 /* 1:abort 0:report */;
  656.     pb->csParam.open.commandTimeoutValue = 0;
  657.     pb->csParam.open.remoteHost = addr->sin_addr.s_addr;
  658.     pb->csParam.open.remotePort = addr->sin_port;
  659.     pb->csParam.open.localHost = 0;
  660.     pb->csParam.open.localPort = fMySocketAddress.sin_port;
  661.     pb->csParam.open.dontFrag = 0;
  662.     pb->csParam.open.timeToLive = 0;
  663.     pb->csParam.open.security = 0;
  664.     pb->csParam.open.optionCnt = 0;
  665.  
  666.     err = PBControlAsync(ParmBlkPtr(pb));
  667.     if (err != 0)
  668.     {
  669.         fSocketState = SKk_STATE_UNCONNECTED;
  670.         return SK_TCPError(err);
  671.     }
  672.  
  673.     if (fNonBlocking)
  674.         return SK_Error(EINPROGRESS);
  675.  
  676.     /* sync connect - spin till TCPActiveOpen completes */
  677.  
  678.     SAFESPIN(pb->ioResult==inProgress, SKk_MISC, 0);
  679.  
  680.     if (errno || pb->ioResult) {
  681.         fSocketState = SKk_STATE_UNCONNECTED;
  682.         
  683.         if (errno)
  684.             return -1;
  685.         else
  686.             return SK_TCPError(pb->ioResult);
  687.     } else
  688.         return 0;
  689. }
  690.  
  691.  
  692. /*************************************************************************** *
  693. * FUNCTION:
  694. *
  695. * CSK_TCPSocket::listen
  696. *
  697. * DESCRIPTION:
  698. *
  699. * Listen for a connection on this MacTCP socket.  When a connection is
  700. * requested, the TCPIOCompletionProc is called to handle establishing
  701. * the connection (which is done by creating a new socket for that connection
  702. * and then returning this socket to a listening state).
  703. *
  704. * PARAMETERS:
  705. *
  706. * int            -- unused
  707. *
  708. * RETURNS:
  709. *
  710. * int            -- Error value (0 = no error).  When error occurs, the global
  711. *                   errno contains a more detailed error value.
  712. *
  713. */
  714.  
  715. int CSK_TCPSocket::listen(int)
  716. {
  717.     OSErr            err;
  718.     TCPiopb *    pb;
  719.  
  720.     if (fSocketState != SKk_STATE_UNCONNECTED)
  721.         return SK_Error(EISCONN);
  722.  
  723.     fSocketState = SKk_STATE_LISTENING;
  724.     pb = GetPB();
  725.     pb->ioCRefNum = SKg_INETSockets.Driver();
  726.     pb->ioCompletion = TCPIOCompletionProc(tcp_listen_done);
  727.     pb->csCode = TCPPassiveOpen;
  728.     pb->csParam.open.validityFlags = timeoutValue | timeoutAction;
  729.     pb->csParam.open.ulpTimeoutValue = 255 /* seconds */;
  730.     pb->csParam.open.ulpTimeoutAction = 0 /* 1:abort 0:report */;
  731.     pb->csParam.open.commandTimeoutValue = 0 /* infinity */;
  732.     pb->csParam.open.remoteHost = 0;
  733.     pb->csParam.open.remotePort = 0;
  734.     pb->csParam.open.localHost = 0;
  735.     pb->csParam.open.localPort = fMySocketAddress.sin_port;
  736.     pb->csParam.open.dontFrag = 0;
  737.     pb->csParam.open.timeToLive = 0;
  738.     pb->csParam.open.security = 0;
  739.     pb->csParam.open.optionCnt = 0;
  740.  
  741.     err = PBControlAsync(ParmBlkPtr(pb));
  742.     if (err != 0) {
  743.         fSocketState = SKk_STATE_UNCONNECTED;
  744.         
  745.         return SK_TCPError(err);
  746.     }
  747.     
  748.     SAFESPIN(!pb->csParam.open.localPort, SKk_MISC, 0);
  749.         
  750.     if (errno) {
  751.         fSocketState = SKk_STATE_UNCONNECTED;
  752.         
  753.         return -1;
  754.     }
  755.  
  756.     fMySocketAddress.sin_addr.s_addr     = pb->csParam.open.localHost;
  757.     fMySocketAddress.sin_port             = pb->csParam.open.localPort;
  758.  
  759.     return 0;
  760. }
  761.  
  762.  
  763. /*************************************************************************** *
  764. * FUNCTION:
  765. *
  766. * CSK_TCPSocket::accept
  767. *
  768. * DESCRIPTION:
  769. *
  770. * Accept a connection request from a given host.
  771. *
  772. * PARAMETERS:
  773. *
  774. * void *            -- The internet number of the requesting host
  775. * int                -- The length of the above address structure
  776. *
  777. * RETURNS:
  778. *
  779. * CSK_Socket *        -- A newly created socket that will handle the newly
  780. *                       established connection (or nil if failed).
  781. *
  782. */
  783.  
  784. CSK_Socket * CSK_TCPSocket::accept(void *from, int *fromlen)
  785. {
  786.     CSK_TCPSocket *        sock;
  787.     TCPiopb *        pb;
  788.     int err;
  789.  
  790.     if (fSocketState == SKk_STATE_UNCONNECTED)
  791.         if (fLastAsyncErr) {
  792.             SK_TCPError(fLastAsyncErr);
  793.             fLastAsyncErr = 0;
  794.  
  795.             return nil;
  796.         } else
  797.             return (CSK_Socket *) SK_Error_nil(ENOTCONN);
  798.  
  799.     if (fSocketState != SKk_STATE_LISTENING && fSocketState != SKk_STATE_LIS_CON)
  800.         return (CSK_Socket *) SK_Error_nil(ENOTCONN);
  801.  
  802.     if (fSocketState == SKk_STATE_LISTENING) {
  803.  
  804.         if (fNonBlocking)
  805.             return (CSK_Socket *) SK_Error_nil(EWOULDBLOCK);
  806.  
  807.         /*    Spin till sock_tcp_listen_done runs. */
  808.         SPINP(fSocketState == SKk_STATE_LISTENING, SKk_MISC, 0);
  809.  
  810.         /* got notification - was it success? */
  811.         if (fSocketState != SKk_STATE_LIS_CON) {
  812.             (void) SK_TCPError(fLastAsyncErr);
  813.             fLastAsyncErr = 0;
  814.             return nil;
  815.         }
  816.     }
  817.  
  818.     /*
  819.      * Have connection.  Duplicate this socket.  The client gets the connection
  820.      * on the new socket and I create a new stream on the old socket and put it
  821.      * in listen state.
  822.      */
  823.     fSocketState     = SKk_STATE_CONNECTED;
  824.     sock        = new CSK_TCPSocket(this);
  825.  
  826.     if (!sock)
  827.     {
  828.         /*    Abort the incoming connection. */
  829.         pb                 = GetPB();
  830.         pb->csCode         = TCPAbort;
  831.  
  832.         PBControlSync(ParmBlkPtr(pb));
  833.  
  834.         fSocketState = SKk_STATE_UNCONNECTED;
  835.  
  836.         // Check for nasty error that once plagued us (will be removed eventually)
  837.         ASSERT(pb->ioResult != inProgress);
  838.  
  839.         /* try and put the socket back in listen mode */
  840.         if (listen(5) < 0)
  841.         {
  842.             fSocketState = SKk_STATE_UNCONNECTED;
  843.             return nil;        /* errno already set */
  844.         }
  845.         return (CSK_Socket *) SK_Error_nil(ENOMEM);
  846.     }
  847.  
  848.     /* Create a new MacTCP stream on the old socket and put it into */
  849.     /* listen state to accept more connections. */
  850.     fSocketState = SKk_STATE_UNCONNECTED;
  851.  
  852.     pb                                = GetPB();
  853.     pb->csCode                         = TCPCreate;
  854.     pb->csParam.create.rcvBuff         = (char *)NewPtr(SKk_StreamBufferSize);
  855.     pb->csParam.create.rcvBuffLen     = SKk_StreamBufferSize;
  856.     pb->csParam.create.notifyProc     = tcp_notify;
  857.     pb->csParam.create.userDataPtr    = Ptr(fSelf);
  858.  
  859.     err = PBControlSync(ParmBlkPtr(pb));
  860.     
  861.     // Check for nasty error that once plagued us (will be removed eventually)
  862.     ASSERT(pb->ioResult != inProgress);
  863.  
  864.     switch(err)
  865.     {
  866.         case noErr:                     break;
  867.         case invalidLength:             return (CSK_Socket *) SK_Error_nil(ENOBUFS);
  868.         case invalidBufPtr:             return (CSK_Socket *) SK_Error_nil(ENOBUFS);
  869.         case insufficientResources:     return (CSK_Socket *) SK_Error_nil(EMFILE);
  870.         default:                         return (CSK_Socket *) SK_Error_nil(ENETDOWN);
  871.     }
  872.  
  873.     fPeerSocketAddress.sin_family         = AF_INET;
  874.     fPeerSocketAddress.sin_addr.s_addr = 0;
  875.     fPeerSocketAddress.sin_port             = 0;
  876.  
  877.     bzero(&fPeerSocketAddress.sin_zero[0], 8);
  878.  
  879.     fLastAsyncErr                 = 0;
  880.     fStream                     = pb->tcpStream;
  881.  
  882.     if (listen(5) < 0) {
  883.         /* nothing to listen on */
  884.         fSocketState = SKk_STATE_UNCONNECTED;
  885.  
  886.         /* kill the incoming connection */
  887.         pb                    = sock->GetPB();
  888.         pb->csCode        = TCPRelease;
  889.  
  890.         if (!PBControlSync(ParmBlkPtr(pb)))
  891.             DisposPtr(pb->csParam.create.rcvBuff); /* there is no release pb */
  892.  
  893.         // Check for nasty error that once plagued us (will be removed eventually)
  894.         ASSERT(pb->ioResult != inProgress);
  895.         
  896.         return nil; /* errno set */
  897.     }
  898.  
  899.     /* return address of partner */
  900.     memcpy(from, &fPeerSocketAddress, *fromlen = MIN(*fromlen, sizeof(struct sockaddr_in)));
  901.  
  902.     return sock;
  903. }
  904.  
  905.  
  906. /*************************************************************************** *
  907. * FUNCTION:
  908. *
  909. * CSK_TCPSocket::recvfrom
  910. *
  911. * DESCRIPTION:
  912. *
  913. * recvfrom() attempts to receive a message (ie a datagram) on this socket
  914. *
  915. * PARAMETERS:
  916. *
  917. * void *        -- Pointer to buffer for returned bytes
  918. * int            -- Maximum number of bytes to read
  919. * int            -- unused
  920. * void *        -- Pointer to memory for return value (address of sender)
  921. * int *            -- Pointer to memory for length of return value
  922. *
  923. * RETURNS:
  924. *
  925. * int            -- Error return (0 = no error), -1 = error in which case
  926. *                   a more specific error code is stored in the global errno:
  927. *
  928. *    ESHUTDOWN    The socket has been shutdown for receive operations.
  929. *
  930. * The bytes received are read into the given buffer.
  931. *
  932. * The internet address of the caller and the length of that address
  933. * are placed into the last two parameters (void * and int).
  934. *
  935. * NOTES:
  936. *
  937. * Typically, read() is used with a TCP stream and recv() with
  938. * UDP where the idea of a message makes more sense. But in fact,
  939. * read() and recv() are equivalent.
  940. *
  941. * Regardless of non-blocking status, if less data is available
  942. * than has been requested, only that much data is returned.
  943. *
  944. * If the socket is marked for non-blocking I/O, and the socket
  945. * is empty, the operation will fail with the error EWOULDBLOCK.
  946. * Otherwise, the operation will block until data is available
  947. * or an error occurs.
  948. *
  949. * A return value of zero indicates that the stream has been
  950. * closed and all data has already been read. ie. end-of-file.
  951. *
  952. */
  953.  
  954. int CSK_TCPSocket::recvfrom(void * buffer, int buflen, int, void * from, int *fromlen)
  955. {
  956.     TCPiopb    *    pb;
  957.     u_long        dataavail;
  958.  
  959.     if (from)
  960.          getpeername(from, fromlen);
  961.     if (fStatus & SKk_STATUS_NOREAD)
  962.         return SK_Error(ESHUTDOWN);
  963.  
  964.     /* socket hasn't finished connecting yet */
  965.     if (fSocketState == SKk_STATE_CONNECTING)
  966.     {
  967.         if (fNonBlocking)
  968.             return SK_Error(EWOULDBLOCK);
  969.  
  970.         /* async connect and sync recv? */
  971.  
  972.         SPIN(fSocketState == SKk_STATE_CONNECTING,SKk_MISC,0);
  973.     }
  974.  
  975.     /* socket is not connected */
  976.     if (!(fSocketState == SKk_STATE_CONNECTED))
  977.     {
  978.         /* see if the connect died (pretty poor test) */
  979.         if (fSocketState == SKk_STATE_UNCONNECTED && fLastAsyncErr != 0 && fLastAsyncErr != 1)
  980.         {
  981.             (void) SK_TCPError(fLastAsyncErr);
  982.             fLastAsyncErr = 0;
  983.             return -1;
  984.         }
  985.  
  986.         /* I guess he just forgot */
  987.         return SK_Error(ENOTCONN);
  988.     }
  989.  
  990.     dataavail = Available();
  991.  
  992.     if (fNonBlocking && !dataavail) 
  993.         return SK_Error(EWOULDBLOCK);
  994.         
  995.     fReceiveBuf    = (char *) buffer;
  996.     fBytesReceived        = 0;
  997.     fLastAsyncErr    = inProgress;
  998.  
  999.     pb = GetPB();
  1000.     pb->ioCompletion = TCPIOCompletionProc(tcp_recv_done);
  1001.     pb->csCode = TCPRcv;
  1002.     pb->csParam.receive.commandTimeoutValue = 0; /* seconds, 0 = blocking */
  1003.     pb->csParam.receive.rcvBuff = fReceiveBuf;
  1004.     pb->csParam.receive.rcvBuffLen = MIN(buflen,SKk_TCPMaxMessageSize);
  1005.  
  1006.     PBControlAsync(ParmBlkPtr(pb));
  1007.  
  1008.     /* This is potentially dangerous, as there doesn't seem to be a way to
  1009.         stop the receive call on an user abort.
  1010.     */
  1011.     SPIN(pb->ioResult==inProgress, SKk_STREAM_READ, buflen);
  1012.  
  1013.     if (pb->ioResult == commandTimeout)
  1014.         pb->ioResult = noErr;
  1015.  
  1016.     switch(pb->ioResult)
  1017.     {
  1018.         case noErr:
  1019.             fLastAsyncErr = noErr;
  1020.  
  1021.             return fBytesReceived;
  1022.  
  1023.         case connectionClosing:
  1024.         case connectionTerminated:
  1025.             return fBytesReceived;
  1026.  
  1027.         case commandTimeout: /* this one should be caught by sock_tcp_recv_done */
  1028.         case connectionDoesntExist:
  1029.         case invalidStreamPtr:
  1030.         case invalidLength:
  1031.         case invalidBufPtr:
  1032.         default:
  1033.             return SK_TCPError(pb->ioResult);
  1034.     }
  1035. }
  1036.  
  1037.  
  1038. /*************************************************************************** *
  1039. * FUNCTION:
  1040. *
  1041. * CSK_TCPSocket::sendto
  1042. *
  1043. * DESCRIPTION:
  1044. *
  1045. * sendto() is used to transmit a message from this socket to another socket.
  1046. *
  1047. * PARAMETERS:
  1048. *
  1049. * void *        -- Pointer to buffer containing bytes to send
  1050. * int            -- The number of bytes to send
  1051. * int            -- Flags (???)
  1052. * void *        -- Pointer to internet address to send to
  1053. * int             -- Length of above internet address structure
  1054. *
  1055. * RETURNS:
  1056. *
  1057. * This call returns the number of bytes sent, or -1 if an error occurred,
  1058. * in which case the global errno contains a more detailed error value:
  1059. *
  1060. *     EINVAL        The sum of the iov_len values in the iov array was
  1061. *                greater than 65535 (TCP) or 65507 (UDP) or there
  1062. *                were too many entries in the array (16 for TCP or
  1063. *                6 for UDP).
  1064. *
  1065. *     ESHUTDOWN    The socket has been shutdown for send operations.
  1066. *
  1067. *     EMSGSIZE    The message is too big to send in one datagram. (UDP)
  1068. *
  1069. *     ENOBUFS        The transmit queue is full. (UDP)
  1070. *
  1071. * The bytes received are read into the given buffer.
  1072. *
  1073. * NOTES:
  1074. *
  1075. * Typically, write() is used with a TCP stream and send() with
  1076. * UDP where the idea of a message makes more sense. But in fact,
  1077. * write() and send() are equivalent.
  1078. *
  1079. * Write() and send() operations are not considered complete
  1080. * until all data has been sent and acknowledged.
  1081. *
  1082. * If a socket is marked for non-blocking I/O, the operation
  1083. * will return an 'error' of EINPROGRESS.
  1084. *
  1085. * If the socket is not marked for non-blocking I/O, the write will
  1086. * block until space becomes available.
  1087. *
  1088. * write() and send() may be used only when the socket is in a connected
  1089. * state, sendto() may be used at any time.
  1090. *
  1091. */
  1092.  
  1093. int CSK_TCPSocket::sendto(void * buffer, int count, int flags, void * to, int)
  1094. {
  1095.     int            bytes,towrite;
  1096.     SKt_MiniWds *    thiswds;
  1097.     short            wdsnum;
  1098.     TCPiopb *    pb;
  1099.     SKt_MiniWds        wdsarray[SKk_TCPMaxWds];
  1100.  
  1101.     if (fStatus & SKk_STATUS_NOWRITE)
  1102.         return SK_Error(ESHUTDOWN);
  1103.  
  1104.     if (to != NULL) /* sendto */
  1105.         return SK_Error(EOPNOTSUPP);
  1106.     if (fSocketState != SKk_STATE_CONNECTED && fSocketState != SKk_STATE_CONNECTING)
  1107.         return SK_Error(ENOTCONN);
  1108.  
  1109.     /* socket hasn't finished connecting yet */
  1110.     if (fSocketState == SKk_STATE_CONNECTING) {
  1111.         if (fNonBlocking) 
  1112.             return SK_Error(EALREADY);
  1113.  
  1114.         /* async connect and sync send? */
  1115.         SPIN(fSocketState == SKk_STATE_CONNECTING, SKk_MISC, 0);
  1116.     }
  1117.  
  1118.     /* socket is not connected */
  1119.     if (!(fSocketState == SKk_STATE_CONNECTED)) {
  1120.         /* see if a previous operation failed */
  1121.         if (fSocketState == SKk_STATE_UNCONNECTED && fLastAsyncErr != 0) {
  1122.             (void) SK_TCPError(fLastAsyncErr);
  1123.             fLastAsyncErr = 0;
  1124.             return -1;
  1125.         }
  1126.  
  1127.         /* I guess he just forgot */
  1128.         return SK_Error(ENOTCONN);
  1129.     }
  1130.  
  1131.     pb                = GetPB();
  1132.     pb->csCode         = TCPStatus;
  1133.  
  1134.     if (PBControlSync(ParmBlkPtr(pb)))
  1135.         bytes = 0;
  1136.     else {
  1137.         bytes = pb->csParam.status.sendWindow - pb->csParam.status.amtUnackedData;
  1138.  
  1139.         if (bytes < 0)
  1140.             bytes = 0;
  1141.     }
  1142.  
  1143.     // Check for nasty error that once plagued us (will be removed eventually)
  1144.     ASSERT(pb->ioResult != inProgress);
  1145.  
  1146.     if (fNonBlocking)
  1147.         if (!bytes) 
  1148.             return SK_Error(EWOULDBLOCK);
  1149.         else if (bytes < count)
  1150.             count = bytes;
  1151.  
  1152.     bytes    =    count;                                        /* save count before we nuke it */
  1153.     memset(wdsarray, 0, SKk_TCPMaxWds*sizeof(SKt_MiniWds));    /* clear up terminus and mark empty */
  1154.     thiswds = wdsarray;
  1155.     wdsnum = 0;
  1156.  
  1157.     while (count > 0) {
  1158.         /* make sure the thing that just finished worked ok */
  1159.         if (fLastAsyncErr) {
  1160.             (void) SK_Error(fLastAsyncErr);
  1161.             fLastAsyncErr = 0;
  1162.             return -1;
  1163.         }
  1164.  
  1165.         towrite=MIN(count,SKk_TCPMaxMessageSize);
  1166.  
  1167.         /* find a clean wds */
  1168.  
  1169.         while (thiswds->length != 0) {
  1170.             wdsnum = (short)((wdsnum+1)%SKk_TCPMaxWds); /* generates compiler warning w/o short - why? */
  1171.             if (wdsnum)
  1172.                 thiswds++;
  1173.             else
  1174.                 thiswds = wdsarray;
  1175.             SPIN(false, SKk_STREAM_WRITE, count);    /* spin once */
  1176.         }
  1177.  
  1178.         /* find a clean pb */
  1179.  
  1180.         thiswds->length    = (short)towrite;
  1181.         thiswds->ptr = (char *) buffer;
  1182.         pb = GetPB();
  1183.         pb->ioCompletion = TCPIOCompletionProc(tcp_send_done);
  1184.         pb->csCode = TCPSend;
  1185.         pb->csParam.send.validityFlags = timeoutValue | timeoutAction;
  1186.         pb->csParam.send.ulpTimeoutValue = 60 /* seconds */;
  1187.         pb->csParam.send.ulpTimeoutAction = 1 /* 0:abort 1:report */;
  1188.         pb->csParam.send.pushFlag = count <= SKk_TCPMaxMessageSize;
  1189.         pb->csParam.send.urgentFlag = flags & MSG_OOB;
  1190.         pb->csParam.send.wdsPtr = (Ptr)thiswds;
  1191.         pb->csParam.send.sendFree = 0;
  1192.         pb->csParam.send.sendLength = 0;
  1193.  
  1194.         PBControlAsync(ParmBlkPtr(pb));
  1195.  
  1196.         SPIN(false, SKk_STREAM_WRITE, count);
  1197.         count     -= towrite;
  1198.         buffer    = (char *) buffer + towrite;
  1199.     }
  1200.  
  1201.     SPIN(pb->ioResult == inProgress, SKk_STREAM_WRITE, 0);
  1202.  
  1203.     if (!pb->ioResult)
  1204.         return(bytes);
  1205.     else
  1206.         return SK_TCPError(pb->ioResult);
  1207. }
  1208.  
  1209.  
  1210. /*************************************************************************** *
  1211. * FUNCTION:
  1212. *
  1213. * CSK_TCPSocket::select
  1214. *
  1215. * DESCRIPTION:
  1216. *
  1217. * Check this socket for readiness to read or write, or for whether
  1218. * it has an exceptional condition pending.  Each of the three
  1219. * flags passed as parameters are set accordingly; only those which
  1220. * were initially set to TRUE are checked.
  1221. *
  1222. * PARAMETERS:
  1223. *
  1224. * Boolean *        -- Can read (???)
  1225. * Boolean *     -- Can write (???)
  1226. * Boolean *        -- Exception (???)
  1227. *
  1228. * RETURNS:
  1229. *
  1230. * int            -- The total number of return flags set to TRUE.
  1231. *
  1232. */
  1233.  
  1234. int CSK_TCPSocket::select(Boolean * canRead, Boolean * canWrite, Boolean * )
  1235. {
  1236.     int        goodies     =     0;
  1237.  
  1238.     if (canRead)
  1239.         switch (fSocketState) {
  1240.             case SKk_STATE_LIS_CON:
  1241.                 *canRead    = true;
  1242.                  ++goodies;
  1243.                 break;
  1244.  
  1245.             case SKk_STATE_CONNECTED:
  1246.                 if (Available()) {
  1247.                     *canRead    = true;
  1248.                     ++goodies;
  1249.                 }
  1250.                 break;
  1251.  
  1252.             case SKk_STATE_UNCONNECTED:
  1253.             case SKk_STATE_CLOSING:
  1254.                 *canRead    = true;        /* CAN THIS REALLY BE CORRECT ??!?!?  S.D. 9/1/93 */
  1255.                 ++goodies;                /* Should either be Available() or FALSE ?? */
  1256.                 break;
  1257.         }
  1258.  
  1259.     if (canWrite) 
  1260.         switch (fSocketState) {
  1261.             case SKk_STATE_CONNECTING:
  1262.                 break;
  1263.             default:
  1264.                 *canWrite = true;
  1265.                 ++goodies;
  1266.         }
  1267.  
  1268.     return goodies;
  1269. }
  1270.  
  1271.  
  1272.  
  1273. /* end of SK_TCP.cc */
  1274.  
  1275.  
  1276.